﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using System.Data;

namespace SweetSQL.Data
{
    internal static class Reflector<T>
        where T : class
    {
        private static TypeInfo _info = new TypeInfo();

        static Reflector()
        {
            object[] attributes = null;
            Type type = null;
            foreach (PropertyInfo property in PropertyCache<T>.Properties.Values)
            {
                if (property.PropertyType.IsGenericType)
                {
                    Type genericDefinition = property.PropertyType.GetGenericTypeDefinition();
                    if (genericDefinition == typeof(Table<>) || genericDefinition.BaseType.GetGenericTypeDefinition() == typeof(Table<>))
                    {
                        type = property.PropertyType.GetGenericArguments()[0];
                        attributes = property.GetCustomAttributes(typeof(TableAttribute), true);
                        foreach (TableAttribute tableAttribute in attributes)
                        {
                            _info.Add(new TableInfo
                                {
                                    Name = string.IsNullOrEmpty(tableAttribute.Name) ? Util.GetTypeName(type) : tableAttribute.Name,
                                    Attribute = tableAttribute,
                                    Property = property,
                                    Type = type,
                                });
                        }
                    }
                }
            }
        }

        public static TableInfo GetTableInfo<TTable>(string name)
            where TTable : class, new()
        {
            TableInfo tableInfo = null;
            if (_info.TableLookup.TryGetValue(name, out tableInfo))
            {
                if (!tableInfo.Reflected)
                {
                    PropertyInfo property = tableInfo.Property;
                    Type instanceType = tableInfo.Type;
                    Dictionary<string, PropertyInfo> properties = PropertyCache.GetProperties(instanceType);

                    foreach (ColumnAttribute columnAttribute in property.GetCustomAttributes(typeof(ColumnAttribute), true))
                    {
                        Util.ThrowIf(string.IsNullOrEmpty(columnAttribute.MemberName), "", "");

                        if (properties.TryGetValue(columnAttribute.MemberName, out property))
                        {
                            tableInfo.Add(new ColumnInfo
                                {
                                    Name = string.IsNullOrEmpty(columnAttribute.ColumnName) ? columnAttribute.MemberName : columnAttribute.ColumnName,
                                    Type = property.PropertyType,
                                    Attribute = columnAttribute,
                                    Property = property,
                                    Get = Dynamic.BuildGet(instanceType, property),
                                    Set = Dynamic.BuildSet(instanceType, property),
                                });
                        }
                        else
                        {
                            throw new ArgumentException();
                        }
                    }
                    tableInfo.Reflected = true;
                }
                return tableInfo;
            }
            else
            {
                throw new ArgumentException();
            }
        }
    }
}
